package com.example.lottery.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.security.SecureRandom;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public final class StringUtils {

    private static final Logger logger = LoggerFactory.getLogger(StringUtils.class);


    private StringUtils() {
    }

    public static String nameMask(final String name) {
        if (isBlank(name)) {
            return name;
        }

        if (name.length() > 3 && name.length() <= 6) {
            return mask(name, 0, 2, name.length() - 2);
        } else if (name.length() <= 3) {
            return mask(name, 0, name.length() - 1, 1);
        } else {
            return mask(name, 1, 2, name.length() - 3);
        }
    }

    public static String cardMask(final String bankCardNo) {
        if (isBlank(bankCardNo)) {
            return bankCardNo;
        }
        if (bankCardNo.length() >= 16) {
            return mask(bankCardNo, 6, 4, bankCardNo.length() - 10);
        } else {
            return mask(bankCardNo);
        }
    }

    public static String certMask(final String idCertNo) {
        if (isBlank(idCertNo)) {
            return idCertNo;
        }
        return mask(idCertNo, 1, 1, idCertNo.length() - 2);
    }

    public static String mobileMask(final String mobile) {
        if (isBlank(mobile)) {
            return mobile;
        }
        String tmp = mobile.trim();
        // 如果是国内手机号，则前三后二
        if (mobile.length() == 11) {
            return mask(tmp, 3, 2, 6);
        }
        int notHideNum = tmp.length() - 4;
        return mask(tmp, notHideNum / 2, notHideNum - notHideNum / 2, 4);
    }

    public static String mask(final String sensitiveData) {
        if (isBlank(sensitiveData)) {
            return sensitiveData;
        }
        String tmp = sensitiveData.trim();
        int length = tmp.length();
        int headNum = (int) Math.ceil(length * 1 / 3.0);
        int tailNum = (int) Math.floor(length * 1 / 3.0);
        return mask(tmp, headNum, tailNum, length - headNum - tailNum);
    }

    public static String mask(final String source, final int frontCharNum, final int tailCharNum, final int hiddenCharNum) {
        if (isBlank(source)) {
            return source;
        }
        String tmp = source.trim();
        int length = tmp.length();
        // 合法性检查，如果参数不合法，返回源数据内容
        if (frontCharNum < 0 || tailCharNum < 0 || hiddenCharNum < 0
                || frontCharNum + tailCharNum > length) {
            return tmp;
        }

        int beginIndex = frontCharNum - 1;
        int endIndex = length - tailCharNum;

        // 原数据前半部分
        StringBuilder result = new StringBuilder();
        if (beginIndex >= 0 && beginIndex < length) {
            result.append(tmp.substring(0, frontCharNum));
        }

        // 中间*
        for (int i = 0; i < hiddenCharNum; i++) {
            result.append('*');
        }

        // 原数据后半部分
        if (endIndex >= 0 && endIndex < length) {
            result.append(tmp.substring(endIndex));
        }

        return result.toString();
    }

    //生成随n位机数
    public static String getRandomNumber(int n) {
        String cardNnumer = "";
        for (int a = 0; a < n; a++) {
            cardNnumer += new SecureRandom().nextInt(10);//生成6位数字
        }
        return cardNnumer;
    }

    public static boolean isEmpty(CharSequence seq) {
        return org.apache.commons.lang3.StringUtils.isEmpty(seq);
    }

    public static boolean isNotEmpty(CharSequence seq) {
        return org.apache.commons.lang3.StringUtils.isNotEmpty(seq);
    }

    public static boolean isBlank(CharSequence seq) {
        return org.apache.commons.lang3.StringUtils.isBlank(seq);
    }

    public static boolean isNotBlank(CharSequence seq) {
        return org.apache.commons.lang3.StringUtils.isNotBlank(seq);
    }

    public static String trim(String str) {
        return org.apache.commons.lang3.StringUtils.trim(str);
    }

    public static String trimToNull(String str) {
        return org.apache.commons.lang3.StringUtils.trimToNull(str);
    }

    public static String trimToEmpty(String str) {
        return org.apache.commons.lang3.StringUtils.trimToEmpty(str);
    }

    public static String strip(String str) {
        return org.apache.commons.lang3.StringUtils.strip(str);
    }

    public static String stripToNull(String str) {
        return org.apache.commons.lang3.StringUtils.stripToNull(str);
    }

    public static String stripToEmpty(String str) {
        return org.apache.commons.lang3.StringUtils.stripToEmpty(str);
    }

    public static String strip(String str, String stripChars) {
        return org.apache.commons.lang3.StringUtils.strip(str, stripChars);
    }

    public static String stripStart(String str, String stripChars) {
        return org.apache.commons.lang3.StringUtils.stripStart(str, stripChars);
    }

    public static String stripEnd(String str, String stripChars) {
        return org.apache.commons.lang3.StringUtils.stripEnd(str, stripChars);
    }

    public static String[] stripAll(String... strs) {
        return org.apache.commons.lang3.StringUtils.stripAll(strs);
    }

    public static String[] stripAll(String[] strs, String stripChars) {
        return org.apache.commons.lang3.StringUtils.stripAll(strs, stripChars);
    }

    public static String stripAccents(String input) {
        return org.apache.commons.lang3.StringUtils.stripAccents(input);
    }

    public static boolean equals(CharSequence seq1, CharSequence seq2) {
        return org.apache.commons.lang3.StringUtils.equals(seq1, seq2);
    }

    public static boolean equalsIgnoreCase(CharSequence str1, CharSequence str2) {
        return org.apache.commons.lang3.StringUtils.equalsIgnoreCase(str1, str2);
    }

    public static int indexOf(CharSequence seq, int searchChar) {
        return org.apache.commons.lang3.StringUtils.indexOf(seq, searchChar);
    }

    public static int indexOf(CharSequence seq, int searchChar, int startPos) {
        return org.apache.commons.lang3.StringUtils.indexOf(seq, searchChar, startPos);
    }

    public static int indexOf(CharSequence seq, CharSequence searchSeq) {
        return org.apache.commons.lang3.StringUtils.indexOf(seq, searchSeq);
    }

    public static int indexOf(CharSequence seq, CharSequence searchSeq, int startPos) {
        return org.apache.commons.lang3.StringUtils.indexOf(seq, searchSeq, startPos);
    }

    public static int ordinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal) {
        return org.apache.commons.lang3.StringUtils.ordinalIndexOf(str, searchStr, ordinal);
    }

    public static int indexOfIgnoreCase(CharSequence str, CharSequence searchStr) {
        return org.apache.commons.lang3.StringUtils.indexOfIgnoreCase(str, searchStr);
    }

    public static int indexOfIgnoreCase(CharSequence str, CharSequence searchStr, int startPos) {
        return org.apache.commons.lang3.StringUtils.indexOfIgnoreCase(str, searchStr, startPos);
    }

    public static int lastIndexOf(CharSequence seq, int searchChar) {
        return org.apache.commons.lang3.StringUtils.lastIndexOf(seq, searchChar);
    }

    public static int lastIndexOf(CharSequence seq, int searchChar, int startPos) {
        return org.apache.commons.lang3.StringUtils.lastIndexOf(seq, searchChar, startPos);
    }

    public static int lastIndexOf(CharSequence seq, CharSequence searchSeq) {
        return org.apache.commons.lang3.StringUtils.lastIndexOf(seq, searchSeq);
    }

    public static int lastIndexOf(CharSequence seq, CharSequence searchSeq, int startPos) {
        return org.apache.commons.lang3.StringUtils.lastIndexOf(seq, searchSeq, startPos);
    }

    public static int lastOrdinalIndexOf(CharSequence str, CharSequence searchStr, int ordinal) {
        return org.apache.commons.lang3.StringUtils.lastOrdinalIndexOf(str, searchStr, ordinal);
    }

    public static int lastIndexOfIgnoreCase(CharSequence str, CharSequence searchStr) {
        return org.apache.commons.lang3.StringUtils.lastIndexOfIgnoreCase(str,
                searchStr);
    }

    public static int lastIndexOfIgnoreCase(CharSequence str, CharSequence searchStr, int startPos) {
        return org.apache.commons.lang3.StringUtils.lastIndexOfIgnoreCase(str, searchStr, startPos);
    }

    public static boolean contains(CharSequence seq, int searchChar) {
        return org.apache.commons.lang3.StringUtils.contains(seq, searchChar);
    }

    public static boolean contains(CharSequence seq, CharSequence searchSeq) {
        return org.apache.commons.lang3.StringUtils.contains(seq, searchSeq);
    }

    public static boolean containsIgnoreCase(CharSequence str, CharSequence searchStr) {
        return org.apache.commons.lang3.StringUtils.containsIgnoreCase(str, searchStr);
    }

    public static boolean containsWhitespace(CharSequence seq) {
        return org.apache.commons.lang3.StringUtils.containsWhitespace(seq);
    }

    public static int indexOfAny(CharSequence seq, char... searchChars) {
        return org.apache.commons.lang3.StringUtils.indexOfAny(seq, searchChars);
    }

    public static int indexOfAny(CharSequence seq, String searchChars) {
        return org.apache.commons.lang3.StringUtils.indexOfAny(seq, searchChars);
    }

    public static boolean containsAny(CharSequence seq, char... searchChars) {
        return org.apache.commons.lang3.StringUtils.containsAny(seq, searchChars);
    }

    public static boolean containsAny(CharSequence seq, CharSequence searchChars) {
        return org.apache.commons.lang3.StringUtils.containsAny(seq, searchChars);
    }

    public static int indexOfAnyBut(CharSequence seq, char... searchChars) {
        return org.apache.commons.lang3.StringUtils.indexOfAnyBut(seq, searchChars);
    }

    public static int indexOfAnyBut(CharSequence seq, CharSequence searchChars) {
        return org.apache.commons.lang3.StringUtils.indexOfAnyBut(seq, searchChars);
    }

    public static boolean containsOnly(CharSequence seq, char... valid) {
        return org.apache.commons.lang3.StringUtils.containsOnly(seq, valid);
    }

    public static boolean containsOnly(CharSequence seq, String validChars) {
        return org.apache.commons.lang3.StringUtils.containsOnly(seq, validChars);
    }

    public static boolean containsNone(CharSequence seq, char... searchChars) {
        return org.apache.commons.lang3.StringUtils.containsNone(seq, searchChars);
    }

    public static boolean containsNone(CharSequence seq, String invalidChars) {
        return org.apache.commons.lang3.StringUtils.containsNone(seq, invalidChars);
    }

    public static int indexOfAny(CharSequence str, CharSequence... searchStrs) {
        return org.apache.commons.lang3.StringUtils.indexOfAny(str, searchStrs);
    }

    public static int lastIndexOfAny(CharSequence str, CharSequence... searchStrs) {
        return org.apache.commons.lang3.StringUtils.lastIndexOfAny(str, searchStrs);
    }

    public static String substring(String str, int start) {
        return org.apache.commons.lang3.StringUtils.substring(str, start);
    }

    public static String substring(String str, int start, int end) {
        return org.apache.commons.lang3.StringUtils.substring(str, start, end);
    }

    public static String left(String str, int len) {
        return org.apache.commons.lang3.StringUtils.left(str, len);
    }

    public static String right(String str, int len) {
        return org.apache.commons.lang3.StringUtils.right(str, len);
    }

    public static String mid(String str, int pos, int len) {
        return org.apache.commons.lang3.StringUtils.mid(str, pos, len);
    }

    public static String substringBefore(String str, String separator) {
        return org.apache.commons.lang3.StringUtils.substringBefore(str, separator);
    }

    public static String substringAfter(String str, String separator) {
        return org.apache.commons.lang3.StringUtils.substringAfter(str, separator);
    }

    public static String substringBeforeLast(String str, String separator) {
        return org.apache.commons.lang3.StringUtils.substringBeforeLast(str, separator);
    }

    public static String substringAfterLast(String str, String separator) {
        return org.apache.commons.lang3.StringUtils.substringAfterLast(str, separator);
    }

    public static String substringBetween(String str, String tag) {
        return org.apache.commons.lang3.StringUtils.substringBetween(str, tag);
    }

    public static String substringBetween(String str, String open, String close) {
        return org.apache.commons.lang3.StringUtils.substringBetween(str, open, close);
    }

    public static String[] substringsBetween(String str, String open, String close) {
        return org.apache.commons.lang3.StringUtils.substringsBetween(str, open, close);
    }

    public static int byteLength(String str) {
        if (str == null) {
            return 0;
        }

        int byteLength = 0;
        try {
            for (int i = 0; i < str.length(); i++) {
                char c = str.charAt(i);
                byteLength = byteLength + String.valueOf(c).getBytes("GBK").length;
            }
        } catch (UnsupportedEncodingException ex) {
            System.err.println(ex);
        }
        return byteLength;
    }

    public static String substringByByteLength(String str, int byteLength) {
        if (StringUtils.isBlank(str)) {
            return str;
        }

        try {
            String strGbk = new String(str.getBytes(), "GBK");
            if (byteLength <= 0 || strGbk.getBytes("GBK").length <= byteLength) {
                return str;
            }

            StringBuilder subStr = new StringBuilder();
            for (int i = 0; i < byteLength; i++) {
                char c = str.charAt(i);
                subStr.append(c);

                int cByteLength = String.valueOf(c).getBytes("GBK").length;
                byteLength = byteLength - (cByteLength - 1);
            }
            return subStr.toString();
        } catch (UnsupportedEncodingException e) {
            return str;
        }
    }

    public static String[] split(String str) {
        return org.apache.commons.lang3.StringUtils.split(str);
    }

    public static String[] split(String str, char separatorChar) {
        return org.apache.commons.lang3.StringUtils.split(str, separatorChar);
    }

    public static String[] split(String str, String separatorChars) {
        return org.apache.commons.lang3.StringUtils.split(str, separatorChars);
    }

    public static String[] split(String str, String separatorChars, int max) {
        return org.apache.commons.lang3.StringUtils.split(str, separatorChars, max);
    }

    public static String[] splitByWholeSeparator(String str, String separator) {
        return org.apache.commons.lang3.StringUtils.splitByWholeSeparator(str, separator);
    }

    public static String[] splitByWholeSeparator(String str, String separator, int max) {
        return org.apache.commons.lang3.StringUtils.splitByWholeSeparator(str, separator, max);
    }

    public static String[] splitByWholeSeparatorPreserveAllTokens(String str, String separator) {
        return org.apache.commons.lang3.StringUtils.splitByWholeSeparatorPreserveAllTokens(str, separator);
    }

    public static String[] splitByWholeSeparatorPreserveAllTokens(String str, String separator, int max) {
        return org.apache.commons.lang3.StringUtils.splitByWholeSeparatorPreserveAllTokens(str, separator, max);
    }

    public static String[] splitPreserveAllTokens(String str) {
        return org.apache.commons.lang3.StringUtils.splitPreserveAllTokens(str);
    }

    public static String[] splitPreserveAllTokens(String str, char separatorChar) {
        return org.apache.commons.lang3.StringUtils.splitPreserveAllTokens(str, separatorChar);
    }

    public static String[] splitPreserveAllTokens(String str, String separatorChars) {
        return org.apache.commons.lang3.StringUtils.splitPreserveAllTokens(str, separatorChars);
    }

    public static String[] splitPreserveAllTokens(String str, String separatorChars, int max) {
        return org.apache.commons.lang3.StringUtils.splitPreserveAllTokens(str, separatorChars, max);
    }

    public static String[] splitByCharacterType(String str) {
        return org.apache.commons.lang3.StringUtils.splitByCharacterType(str);
    }

    public static String[] splitByCharacterTypeCamelCase(String str) {
        return org.apache.commons.lang3.StringUtils.splitByCharacterTypeCamelCase(str);
    }

    public static String join(Object... elements) {
        return org.apache.commons.lang3.StringUtils.join(elements);
    }

    public static String join(Object[] array, char separator) {
        return org.apache.commons.lang3.StringUtils.join(array, separator);
    }

    public static String join(long[] array, char separator) {
        return org.apache.commons.lang3.StringUtils.join(array, separator);
    }

    public static String join(int[] array, char separator) {
        return org.apache.commons.lang3.StringUtils.join(array, separator);
    }

    public static String join(short[] array, char separator) {
        return org.apache.commons.lang3.StringUtils.join(array, separator);
    }

    public static String join(byte[] array, char separator) {
        return org.apache.commons.lang3.StringUtils.join(array, separator);
    }

    public static String join(char[] array, char separator) {
        return org.apache.commons.lang3.StringUtils.join(array, separator);
    }

    public static String join(float[] array, char separator) {
        return org.apache.commons.lang3.StringUtils.join(array, separator);
    }

    public static String join(double[] array, char separator) {
        return org.apache.commons.lang3.StringUtils.join(array, separator);
    }

    public static String join(Object[] array, String separator) {
        return org.apache.commons.lang3.StringUtils.join(array, separator);
    }

    public static String join(Object[] array, char separator, int startIndex, int endIndex) {
        return org.apache.commons.lang3.StringUtils.join(array, separator, startIndex, endIndex);
    }

    public static String join(long[] array, char separator, int startIndex, int endIndex) {
        return org.apache.commons.lang3.StringUtils.join(array, separator, startIndex, endIndex);
    }

    public static String join(int[] array, char separator, int startIndex, int endIndex) {
        return org.apache.commons.lang3.StringUtils.join(array, separator, startIndex, endIndex);
    }

    public static String join(byte[] array, char separator, int startIndex, int endIndex) {
        return org.apache.commons.lang3.StringUtils.join(array, separator, startIndex, endIndex);
    }

    public static String join(short[] array, char separator, int startIndex, int endIndex) {
        return org.apache.commons.lang3.StringUtils.join(array, separator, startIndex, endIndex);
    }

    public static String join(char[] array, char separator, int startIndex, int endIndex) {
        return org.apache.commons.lang3.StringUtils.join(array, separator, startIndex, endIndex);
    }

    public static String join(double[] array, char separator, int startIndex, int endIndex) {
        return org.apache.commons.lang3.StringUtils.join(array, separator, startIndex, endIndex);
    }

    public static String join(float[] array, char separator, int startIndex, int endIndex) {
        return org.apache.commons.lang3.StringUtils.join(array, separator, startIndex, endIndex);
    }

    public static String join(Object[] array, String separator, int startIndex, int endIndex) {
        return org.apache.commons.lang3.StringUtils.join(array, separator, startIndex, endIndex);
    }

    public static String join(Iterator<?> iterator, char separator) {
        return org.apache.commons.lang3.StringUtils.join(iterator, separator);
    }

    public static String join(Iterator<?> iterator, String separator) {
        return org.apache.commons.lang3.StringUtils.join(iterator, separator);
    }

    public static String join(Iterable<?> iterable, char separator) {
        return org.apache.commons.lang3.StringUtils.join(iterable, separator);
    }

    public static String join(Iterable<?> iterable, String separator) {
        return org.apache.commons.lang3.StringUtils.join(iterable, separator);
    }

    public static String deleteWhitespace(String str) {
        return org.apache.commons.lang3.StringUtils.deleteWhitespace(str);
    }

    public static String removeStart(String str, String remove) {
        return org.apache.commons.lang3.StringUtils.removeStart(str, remove);
    }

    public static String removeStartIgnoreCase(String str, String remove) {
        return org.apache.commons.lang3.StringUtils.removeStartIgnoreCase(str, remove);
    }

    public static String removeEnd(String str, String remove) {
        return org.apache.commons.lang3.StringUtils.removeEnd(str, remove);
    }

    public static String removeEndIgnoreCase(String str, String remove) {
        return org.apache.commons.lang3.StringUtils.removeEndIgnoreCase(str, remove);
    }

    public static String remove(String str, String remove) {
        return org.apache.commons.lang3.StringUtils.remove(str, remove);
    }

    public static String remove(String str, char remove) {
        return org.apache.commons.lang3.StringUtils.remove(str, remove);
    }

    public static String replaceOnce(String str, String searchString, String replacement) {
        return org.apache.commons.lang3.StringUtils.replaceOnce(str, searchString, replacement);
    }

    public static String replace(String str, String searchString, String replacement) {
        return org.apache.commons.lang3.StringUtils.replace(str, searchString, replacement);
    }

    public static String replace(String str, String searchString, String replacement, int max) {
        return org.apache.commons.lang3.StringUtils.replace(str, searchString, replacement, max);
    }

    public static String replaceEach(String str, String[] searchList, String[] replacementList) {
        return org.apache.commons.lang3.StringUtils.replaceEach(str, searchList, replacementList);
    }

    public static String replaceEachRepeatedly(String str, String[] searchList, String[] replacementList) {
        return org.apache.commons.lang3.StringUtils.replaceEachRepeatedly(str, searchList, replacementList);
    }

    public static String replaceChars(String str, char searchChar, char replaceChar) {
        return org.apache.commons.lang3.StringUtils.replaceChars(str, searchChar, replaceChar);
    }

    public static String replaceChars(String str, String searchChars, String replaceChars) {
        return org.apache.commons.lang3.StringUtils.replaceChars(str, searchChars, replaceChars);
    }

    public static String overlay(String str, String overlay, int start, int end) {
        return org.apache.commons.lang3.StringUtils.overlay(str, overlay, start, end);
    }

    public static String chomp(String str) {
        return org.apache.commons.lang3.StringUtils.chomp(str);
    }

    public static String chop(String str) {
        return org.apache.commons.lang3.StringUtils.chop(str);
    }

    public static String repeat(String str, int repeat) {
        return org.apache.commons.lang3.StringUtils.repeat(str, repeat);
    }

    public static String repeat(String str, String separator, int repeat) {
        return org.apache.commons.lang3.StringUtils.repeat(str, separator, repeat);
    }

    public static String repeat(char ch, int repeat) {
        return org.apache.commons.lang3.StringUtils.repeat(ch, repeat);
    }

    public static String rightPad(String str, int size) {
        return org.apache.commons.lang3.StringUtils.rightPad(str, size);
    }

    public static String rightPad(String str, int size, char padChar) {
        return org.apache.commons.lang3.StringUtils.rightPad(str, size, padChar);
    }

    public static String rightPad(String str, int size, String padStr) {
        return org.apache.commons.lang3.StringUtils.rightPad(str, size, padStr);
    }

    public static String leftPad(String str, int size) {
        return org.apache.commons.lang3.StringUtils.leftPad(str, size);
    }

    public static String leftPad(String str, int size, char padChar) {
        return org.apache.commons.lang3.StringUtils.leftPad(str, size, padChar);
    }

    public static String leftPad(String str, int size, String padStr) {
        return org.apache.commons.lang3.StringUtils.leftPad(str, size, padStr);
    }

    public static int length(CharSequence cs) {
        return org.apache.commons.lang3.StringUtils.length(cs);
    }

    public static String center(String str, int size) {
        return org.apache.commons.lang3.StringUtils.center(str, size);
    }

    public static String center(String str, int size, char padChar) {
        return org.apache.commons.lang3.StringUtils.center(str, size, padChar);
    }

    public static String center(String str, int size, String padStr) {
        return org.apache.commons.lang3.StringUtils.center(str, size, padStr);
    }

    public static String upperCase(String str) {
        return org.apache.commons.lang3.StringUtils.upperCase(str);
    }

    public static String upperCase(String str, Locale locale) {
        return org.apache.commons.lang3.StringUtils.upperCase(str, locale);
    }

    public static String lowerCase(String str) {
        return org.apache.commons.lang3.StringUtils.lowerCase(str);
    }

    public static String lowerCase(String str, Locale locale) {
        return org.apache.commons.lang3.StringUtils.lowerCase(str, locale);
    }

    public static String capitalize(String str) {
        return org.apache.commons.lang3.StringUtils.capitalize(str);
    }

    public static String uncapitalize(String str) {
        return org.apache.commons.lang3.StringUtils.uncapitalize(str);
    }

    public static String swapCase(String str) {
        return org.apache.commons.lang3.StringUtils.swapCase(str);
    }

    public static int countMatches(CharSequence str, CharSequence sub) {
        return org.apache.commons.lang3.StringUtils.countMatches(str, sub);
    }

    public static boolean isAlpha(CharSequence cs) {
        return org.apache.commons.lang3.StringUtils.isAlpha(cs);
    }

    public static boolean isAlphaSpace(CharSequence cs) {
        return org.apache.commons.lang3.StringUtils.isAlphaSpace(cs);
    }

    public static boolean isAlphanumeric(CharSequence cs) {
        return org.apache.commons.lang3.StringUtils.isAlphanumeric(cs);
    }

    public static boolean isAlphanumericSpace(CharSequence cs) {
        return org.apache.commons.lang3.StringUtils.isAlphanumericSpace(cs);
    }

    public static boolean isAsciiPrintable(CharSequence cs) {
        return org.apache.commons.lang3.StringUtils.isAsciiPrintable(cs);
    }

    private final static String REGEX_INT = "-?[1-9]\\d*$";
    private final static String REGEX_DECIMAL = "-?([1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*|0?\\.0+|0)$";

    public static boolean isIntOrDecimal(String str) {
        if (StringUtils.isBlank(str))
            return false;

        return str.matches(REGEX_INT) || str.matches(REGEX_DECIMAL);
    }

    public static boolean isNumeric(CharSequence cs) {
        if (cs == null)
            return false;

        return org.apache.commons.lang3.StringUtils.isNumeric(cs);
    }

    public static boolean isNumericSpace(CharSequence cs) {
        if (cs == null)
            return false;

        return org.apache.commons.lang3.StringUtils.isNumericSpace(cs);
    }

    public static boolean isWhitespace(CharSequence cs) {
        return org.apache.commons.lang3.StringUtils.isWhitespace(cs);
    }

    public static boolean isAllLowerCase(CharSequence cs) {
        return org.apache.commons.lang3.StringUtils.isAllLowerCase(cs);
    }

    public static boolean isAllUpperCase(CharSequence cs) {
        return org.apache.commons.lang3.StringUtils.isAllUpperCase(cs);
    }

    public static String defaultString(String str) {
        return org.apache.commons.lang3.StringUtils.defaultString(str);
    }

    public static String defaultString(String str, String defaultStr) {
        return org.apache.commons.lang3.StringUtils.defaultString(str, defaultStr);
    }

    public static <T extends CharSequence> T defaultIfBlank(T str, T defaultStr) {
        return org.apache.commons.lang3.StringUtils.defaultIfBlank(str, defaultStr);
    }

    public static <T extends CharSequence> T defaultIfEmpty(T str, T defaultStr) {
        return org.apache.commons.lang3.StringUtils.defaultIfEmpty(str, defaultStr);
    }

    public static String reverse(String str) {
        return org.apache.commons.lang3.StringUtils.reverse(str);
    }

    public static String reverseDelimited(String str, char separatorChar) {
        return org.apache.commons.lang3.StringUtils.reverseDelimited(str, separatorChar);
    }

    public static String abbreviate(String str, int maxWidth) {
        return org.apache.commons.lang3.StringUtils.abbreviate(str, maxWidth);
    }

    public static String abbreviate(String str, int offset, int maxWidth) {
        return org.apache.commons.lang3.StringUtils.abbreviate(str, offset, maxWidth);
    }

    public static String abbreviateMiddle(String str, String middle, int length) {
        return org.apache.commons.lang3.StringUtils.abbreviateMiddle(str, middle, length);
    }

    public static String difference(String str1, String str2) {
        return org.apache.commons.lang3.StringUtils.difference(str1, str2);
    }

    public static int indexOfDifference(CharSequence cs1, CharSequence cs2) {
        return org.apache.commons.lang3.StringUtils.indexOfDifference(cs1, cs2);
    }

    public static int indexOfDifference(CharSequence... css) {
        return org.apache.commons.lang3.StringUtils.indexOfDifference(css);
    }

    public static String getCommonPrefix(String... strs) {
        return org.apache.commons.lang3.StringUtils.getCommonPrefix(strs);
    }

    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
        return org.apache.commons.lang3.StringUtils.getLevenshteinDistance(s, t);
    }

    public static int getLevenshteinDistance(CharSequence s, CharSequence t, int threshold) {
        return org.apache.commons.lang3.StringUtils.getLevenshteinDistance(s, t, threshold);
    }

    public static boolean startsWith(CharSequence cs, CharSequence prefix) {
        return org.apache.commons.lang3.StringUtils.startsWith(cs, prefix);
    }

    public static boolean startsWithIgnoreCase(CharSequence cs, CharSequence prefix) {
        return org.apache.commons.lang3.StringUtils.startsWithIgnoreCase(cs, prefix);
    }

    public static boolean startsWithAny(CharSequence cs, CharSequence... searchStrings) {
        return org.apache.commons.lang3.StringUtils.startsWithAny(cs, searchStrings);
    }

    public static boolean endsWith(CharSequence cs, CharSequence suffix) {
        return org.apache.commons.lang3.StringUtils.endsWith(cs, suffix);
    }

    public static boolean endsWithIgnoreCase(CharSequence cs, CharSequence suffix) {
        return org.apache.commons.lang3.StringUtils.endsWithIgnoreCase(cs, suffix);
    }

    public static String normalizeSpace(String str) {
        return org.apache.commons.lang3.StringUtils.normalizeSpace(str);
    }

    public static boolean endsWithAny(CharSequence cs, CharSequence... searchStrings) {
        return org.apache.commons.lang3.StringUtils.endsWithAny(cs, searchStrings);
    }

    public static String toString(byte[] bytes, String charsetName) throws UnsupportedEncodingException {
        return org.apache.commons.lang3.StringUtils.toString(bytes, charsetName);
    }

    public static int compare(String str1, String str2) {
        if (str1 == null && str2 == null)
            return 0;
        else if (str1 != null && str2 == null)
            return -1;
        else if (str1 == null && str2 != null)
            return 1;
        else
            return str1.compareTo(str2);
    }

    public static String convertIntegerToFixedLengthString(int number, int digits) {
        StringBuilder string = new StringBuilder();

        int numberDigits = digits(number);

        if (numberDigits > digits)
            throw new NullPointerException("Number: " + number + "; Digits: " + digits + ".");

        while (digits > numberDigits) {
            string.append("0");
            digits--;
        }
        string.append(number);

        return string.toString();
    }

    public static String convertLongToFixedLengthString(long number, int digits) {
        StringBuilder string = new StringBuilder();

        int numberDigits = digits(number);

        if (numberDigits > digits)
            throw new NullPointerException("Number: " + number + "; Digits: " + digits + ".");

        while (digits > numberDigits) {
            string.append("0");
            digits--;
        }
        string.append(number);

        return string.toString();
    }

    private static int digits(int number) {
        return String.valueOf(number).replaceAll("-", "").length();
    }

    private static int digits(long number) {
        return String.valueOf(number).replaceAll("-", "").length();
    }

    public static final String SYSTEM_CHARSET = System.getProperty(
            "file.encoding", "utf-8");

    /**
     * The predefined line delimiters
     */
    private static final char[] CR = {'\r'};

    private static final char[] LF = {'\n'};

    private static final char[] CRLF = {'\r', '\n'};

    private static final char[] EMPTY = {};

    public static final String DEFAULT_CHARACTERS_REQUIRED_IN_PATH = ".";

    public static final boolean DEFAULT_UNICODIFY_ALL = false;

    public static final int DEFAULT_BASE64_LINE_LENGTH = 100;

    /**
     * @param string in the "camel" notation like "beMyCamel"
     * @return the resulting string in usual notation like "be_my_camel"
     */
    public static String fromCamelToUnderscore(String string) {
        int size = string.length();
        StringBuffer sb = new StringBuffer(size);
        for (int i = 0; i < size; i++) {
            char c = string.charAt(i);
            if (i > 0 && i < size - 1) {
                char next = string.charAt(i + 1);
                char prev = string.charAt(i - 1);
                if (Character.isUpperCase(c) && Character.isJavaIdentifierPart(next)
                        && Character.isJavaIdentifierPart(prev) && !Character.isUpperCase(next)) {
                    sb.append('_');
                    c = Character.toLowerCase(c);
                }
            }
            sb.append(c);
        }
        return sb.toString();
    }

    /**
     * @param string in the "underscore" notation like "be_my_camel"
     * @return the resulting string in "camel" notation like "beMyCamel"
     */
    public static String fromUnderscoreToCamel(String string) {
        int size = string.length();
        StringBuffer sb = new StringBuffer(size);
        boolean skipChar = false;
        boolean toUpper = false;
        for (int i = 0; i < size; i++) {
            char c = string.charAt(i);
            skipChar = i > 0 && c == '_';
            if (skipChar && i < size - 1 && !Character.isJavaIdentifierPart(string.charAt(i + 1))) {
                skipChar = false;
            } else if (i == size - 1) {
                skipChar = false;
            }
            if (!skipChar) {
                if (toUpper) {
                    sb.append(Character.toUpperCase(c));
                } else {
                    if (i > 0) {
                        if (Character.isJavaIdentifierPart(string.charAt(i - 1))) {
                            sb.append(Character.toLowerCase(c));
                        } else {
                            sb.append(c);
                        }
                    } else {
                        sb.append(Character.toLowerCase(c));
                    }
                }
            }
            toUpper = skipChar;
        }
        return sb.toString();
    }

    /**
     * Search for occurencies of line references in text, like
     * <p>
     * <pre>
     * foo/Foo.java:156
     * </pre>
     *
     * @return integer value guessed as line reference in text (this is not a
     * offset in given line!!!)
     */
    public static int findLineReference(String line, int startOffset) {
        if (line == null || line.length() == 0 || startOffset >= line.length() || startOffset < 0) {
            return -1; // shit in, shit out
        }

        // search for first ':', if any
        int doppIndx = line.indexOf(':', startOffset);

        // means > -1 and not the same occurence
        if (doppIndx > startOffset) {
            // try to find most common occurence: after first ':'
            int firstTry = findLineReference(line, doppIndx);
            // found? ok.
            if (firstTry >= 0) {
                return firstTry;
            }
            // else: we doesn't have line info after ':' or it is before!
        }

        int startChar = -1, stopChar = -1;
        boolean digit;
        for (int i = startOffset; i < line.length(); i++) {
            digit = Character.isDigit(line.charAt(i));
            if (digit) {
                if (startChar < 0) {
                    // let see on pevious character: is it letter, then
                    // followed digit cannot be line number, but is part of
                    // path or java name like 6 in Base64.java:125
                    if (i - 1 >= 0 && Character.isLetter(line.charAt(i - 1))) {
                        continue;
                    }
                    startChar = i;
                }
                stopChar = i + 1;
            } else if (startChar >= 0) {
                stopChar = i;
                break;
            }
        }
        if (startChar >= 0 && stopChar > 0) {
            line = line.substring(startChar, stopChar);
            int result = Integer.parseInt(line);
            return result;
        }
        return -1;
    }

    public static int indexOf(String line, char c, int startOffset, int stopOffset, boolean forward) {
        int i = startOffset;
        while (forward ? i < stopOffset : i > stopOffset) {
            if (line.charAt(i) == c) {
                return i;
            }
            if (forward) {
                i++;
            } else {
                i--;
            }
        }
        return -1;
    }

    /**
     * @param charset      non null
     * @param text         non null
     * @param unicodeValue
     * @return null if text could be encoded, error message otherwise
     */
    public static String canEncode(String charset, CharSequence text, String unicodeValue) {
        Charset cs;
        try {
            cs = Charset.forName(charset);
        } catch (IllegalCharsetNameException ex) {
            return "Charset name '" + charset + "' is illegal.";
        } catch (UnsupportedCharsetException ex) {
            return "Charset '" + charset + "' is not supported.";
        }
        if (cs.canEncode() && cs.newEncoder().canEncode(text)) {
            return null;
        }
        return "Charset '" + charset + "' does not support encoding for \\u" + unicodeValue + ".";
    }

    public static boolean convertTabsToSpaces(
            StringBuffer line, int tabWidth, boolean removeTrailing, boolean replaceAllTabs, boolean useModulo4Tabs) {
        char lastChar;
        boolean changed = false;
        if (removeTrailing) {
            changed = removeTrailingSpace(line);
        }
        int lineLength = line.length();
        int spacesCount = 0;
        int tabsCount = 0;
        int lastIdx = 0;
        for (; lastIdx < lineLength; lastIdx++) {
            lastChar = line.charAt(lastIdx);
            if (lastChar == '\t') {
                changed = true;
                tabsCount++;
            } else if (lastChar == ' ') {
                spacesCount++;
            } else {
                break;
            }
        }
        if (tabsCount > 0) {
            spacesCount = calculateSpaces4Tabs(spacesCount, tabsCount, tabWidth, useModulo4Tabs);

            // delete whitespace to 'last' index, replace with spaces
            line.delete(0, lastIdx);
            line.insert(0, fillWith(spacesCount, ' '));
        }
        if (replaceAllTabs) {
            if (lastIdx >= lineLength) {
                lastIdx = 0;
            }
            changed |= replaceAllTabs(line, lastIdx, tabWidth);
        }
        return changed;
    }

    private static int calculateSpaces4Tabs(int spacesCount, int tabsCount, int tabWidth, boolean useModulo4Tabs) {
        if (!useModulo4Tabs) {
            return spacesCount + tabsCount * tabWidth;
        }
        /*
         * This does work well if and only if all three conditions below are
         * met: 1) the same tab size was used as the one set in AnyEdit
         * preferences 2) spaces wasn't "cross over" mixed with tabs multiple
         * times in a line 3) spaces prepends tabs
         */
        return spacesCount - (spacesCount % tabWidth) + tabsCount * tabWidth;
    }

    private static int calculateTabs4Spaces(int spacesCount, int tabWidth) {
        int tabs = spacesCount / tabWidth;
        int rest = spacesCount % tabWidth != 0 ? 1 : 0;
        return tabs + rest;
    }

    private static boolean replaceAllTabs(StringBuffer line, int start, int tabWidth) {
        String spaces = null;
        boolean changed = false;
        for (int i = start; i < line.length(); i++) {
            char c = line.charAt(i);
            if (c == '\t') {
                if (spaces == null) {
                    spaces = String.valueOf(fillWith(tabWidth, ' '));
                }
                line.replace(i, i + 1, spaces);
                changed = true;
            }
        }
        return changed;
    }

    private static boolean replaceAllSpaces(StringBuffer line, int start, int tabWidth) {
        boolean changed = false;
        int spacesCount = 0;
        int lastIdx = start;
        int firstIdx = start;
        for (; lastIdx < line.length(); lastIdx++) {
            char c = line.charAt(lastIdx);
            if (c == ' ') {
                if (spacesCount == 0) {
                    firstIdx = lastIdx;
                }
                spacesCount++;
            } else if (spacesCount > 0) {
                int tabsCount = calculateTabs4Spaces(spacesCount, tabWidth);
                line.replace(firstIdx, lastIdx, String.valueOf(fillWith(tabsCount, '\t')));
                changed = true;
                spacesCount = 0;
                lastIdx = firstIdx + tabsCount;
            }
        }
        if (spacesCount > 0) {
            int tabsCount = calculateTabs4Spaces(spacesCount, tabWidth);
            line.replace(firstIdx, lastIdx, String.valueOf(fillWith(tabsCount, '\t')));
            changed = true;
        }
        return changed;
    }

    public static boolean removeTrailingSpace(StringBuffer line) {
        boolean changed = false;
        char lastChar;
        int lineLength = line.length();
        int lastCharsLength = getLineEnd(line).length;
        int lastIdx = lineLength - lastCharsLength - 1;
        while (lastIdx >= 0) {
            lastChar = line.charAt(lastIdx);
            if (lastChar != ' ' && lastChar != '\t') {
                break;
            }
            lastIdx--;
        }
        if (lastIdx != lineLength - lastCharsLength - 1) {
            line.delete(lastIdx + 1, lineLength - lastCharsLength);
            changed = true;
        }

        return changed;
    }

    public static boolean convertSpacesToTabs(StringBuffer line, int tabWidth, boolean removeTrailing, boolean replaceAllSpaces) {
        boolean changed = false;
        if (removeTrailing) {
            changed = removeTrailingSpace(line);
        }
        int lineLength = line.length();
        int spacesCount = 0;
        int tabsCount = 0;
        int lastIdx = 0;
        char lastChar = '?';
        for (; lastIdx < lineLength; lastIdx++) {
            lastChar = line.charAt(lastIdx);
            if (lastChar == ' ') {
                changed = true;
                spacesCount++;
            } else if (lastChar == '\t') {
                tabsCount++;
            } else {
                break;
            }
        }

        if (spacesCount > 0) {
            boolean isComment = lastChar == '*';
            int additionalTabs = spacesCount / tabWidth;
            if (additionalTabs == 0 && tabsCount == 0) {
                if (replaceAllSpaces) {
                    additionalTabs = 1;
                    spacesCount = 0;
                } else {
                    if (!isComment) {
                        line.delete(0, lastIdx);
                        changed = true;
                    }
                    return changed;
                }
            }
            if (additionalTabs == 0 && !replaceAllSpaces) {
                line.delete(0, tabsCount + spacesCount);
                if (tabsCount > 0) {
                    line.insert(0, fillWith(tabsCount, '\t'));
                }
                if (isComment) {
                    line.insert(tabsCount, fillWith(1, ' '));
                }
                return true;
            }
            tabsCount += additionalTabs;
            // modulo rest
            int extraSpaces = spacesCount % tabWidth;

            // delete whitespace to 'last' index, replace with tabs
            line.delete(0, lastIdx);
            line.insert(0, fillWith(tabsCount, '\t'));
            // if some last spaces exists, add them back
            if (extraSpaces > 0) {
                if (replaceAllSpaces) {
                    line.insert(tabsCount, fillWith(1, '\t'));
                } else {
                    line.insert(tabsCount, fillWith(extraSpaces, ' '));
                }
            }
        }
        if (replaceAllSpaces) {
            changed |= replaceAllSpaces(line, tabsCount, tabWidth);
        }
        return changed;
    }

    private static char[] getLineEnd(StringBuffer line) {
        if (line == null) {
            return EMPTY;
        }
        int lastIdx = line.length() - 1;
        if (lastIdx < 0) {
            return EMPTY;
        }
        char last = line.charAt(lastIdx);
        if (last == '\n') {
            if (lastIdx > 0) {
                if (line.charAt(lastIdx - 1) == '\r') {
                    return CRLF; // windows
                }
            }
            return LF; // unix
        } else if (last == '\r') {
            return CR; // mac
        } else {
            return EMPTY;
        }
    }

    /**
     * @return number of occurencies of c in s
     */
    public static int count(String s, char c) {
        if (s == null) {
            return 0;
        }
        int count = 0;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == c) {
                count++;
            }
        }
        return count;
    }

    /**
     * @return char array with specified amount of given characters.
     */
    private static char[] fillWith(int length, char c) {
        char[] chars = new char[length];
        for (int i = 0; i < length; i++) {
            chars[i] = c;
        }
        return chars;
    }

    /**
     * Characters used for escape operations
     */
    private static final String[][] HTML_ESCAPE_CHARS = {{"&lt;", "<"},
            {"&gt;", ">"}, {"&amp;", "&"}, {"&quot;", "\""},
            {"&agrave;", "à"}, {"&Agrave;", "À"}, {"&acirc;", "â"},
            {"&auml;", "ä"}, {"&Auml;", "Ä"}, {"&Acirc;", "Â"},
            {"&aring;", "å"}, {"&Aring;", "Å"}, {"&aelig;", "æ"},
            {"&AElig;", "Æ"}, {"&ccedil;", "ç"}, {"&Ccedil;", "Ç"},
            {"&eacute;", "é"}, {"&Eacute;", "É"}, {"&aacute;", "á"},
            {"&Aacute;", "Á"}, {"&egrave;", "è"}, {"&Egrave;", "È"},
            {"&ecirc;", "ê"}, {"&Ecirc;", "Ê"}, {"&euml;", "ë"},
            {"&Euml;", "Ë"}, {"&iuml;", "ï"}, {"&Iuml;", "Ï"},
            {"&iacute;", "í"}, {"&Iacute;", "Í"}, {"&atilde;", "ã"},
            {"&Atilde;", "Ã"}, {"&otilde;", "õ"}, {"&Otilde;", "Õ"},
            {"&oacute;", "ó"}, {"&Oacute;", "Ó"}, {"&ocirc;", "ô"},
            {"&Ocirc;", "Ô"}, {"&ouml;", "ö"}, {"&Ouml;", "Ö"},
            {"&oslash;", "ø"}, {"&Oslash;", "Ø"}, {"&szlig;", "ß"},
            {"&ugrave;", "ù"}, {"&Ugrave;", "Ù"}, {"&uacute;", "ú"},
            {"&Uacute;", "Ú"}, {"&ucirc;", "û"}, {"&Ucirc;", "Û"},
            {"&uuml;", "ü"}, {"&Uuml;", "Ü"}, {"&nbsp;", " "},
            {"&reg;", "\u00AE"}, {"&copy;", "\u00A9"},
            {"&euro;", "\u20A0"}, {"&#8364;", "\u20AC"}

    };

    /**
     * Get html entity for escape character
     *
     * @return null, if no entity found for given character
     */
    public static String getEntityForChar(char ch) {
        switch (ch) {
            case '<':
                return "&lt;";
            case '>':
                return "&gt;";
            case '&':
                return "&amp;";
            case '"':
                return "&quot;";
            case 'à':
                return "&agrave;";
            case 'á':
                return "&aacute;";
            case 'À':
                return "&Agrave;";
            case 'Á':
                return "&Aacute;";
            case 'â':
                return "&acirc;";
            case 'Â':
                return "&Acirc;";
            case 'ä':
                return "&auml;";
            case 'Ä':
                return "&Auml;";
            case 'å':
                return "&aring;";
            case 'Å':
                return "&Aring;";
            case 'ã':
                return "&atilde;";
            case 'Ã':
                return "&Atilde;";
            case 'æ':
                return "&aelig;";
            case 'Æ':
                return "&AElig;";
            case 'ç':
                return "&ccedil;";
            case 'Ç':
                return "&Ccedil;";
            case 'é':
                return "&eacute;";
            case 'É':
                return "&Eacute;";
            case 'è':
                return "&egrave;";
            case 'È':
                return "&Egrave;";
            case 'ê':
                return "&ecirc;";
            case 'Ê':
                return "&Ecirc;";
            case 'ë':
                return "&euml;";
            case 'Ë':
                return "&Euml;";
            case 'í':
                return "&iacute;";
            case 'Í':
                return "&Iacute;";
            case 'ï':
                return "&iuml;";
            case 'Ï':
                return "&Iuml;";
            case 'õ':
                return "&otilde;";
            case 'Õ':
                return "&Otilde;";
            case 'ó':
                return "&oacute;";
            case 'ô':
                return "&ocirc;";
            case 'Ó':
                return "&Oacute;";
            case 'Ô':
                return "&Ocirc;";
            case 'ö':
                return "&ouml;";
            case 'Ö':
                return "&Ouml;";
            case 'ø':
                return "&oslash;";
            case 'Ø':
                return "&Oslash;";
            case 'ß':
                return "&szlig;";
            case 'ù':
                return "&ugrave;";
            case 'Ù':
                return "&Ugrave;";
            case 'ú':
                return "&uacute;";
            case 'Ú':
                return "&Uacute;";
            case 'û':
                return "&ucirc;";
            case 'Û':
                return "&Ucirc;";
            case 'ü':
                return "&uuml;";
            case 'Ü':
                return "&Uuml;";
            case '\u00AE':
                return "&reg;";
            case '\u00A9':
                return "&copy;";
            case '\u20A0':
                return "&euro;";
            case '\u20AC':
                return "&#8364;";
            // case '' : return "&euro;";
            // case '\u20AC': return "&#x20AC;"; // euro

            // be carefull with this one (non-breaking white space)
            // case ' ' : return "&nbsp;";
            default: {
                int ci = 0xffff & ch;
                if (ci < 160) {
                    // nothing special only 7 Bit
                    return null;
                }
                // Not 7 Bit use the unicode system
                return "&#" + ci + ";";
            }
        }
    }

    /**
     * change escape characters to html entities (from
     * http://www.rgagnon.com/howto.html)
     *
     * @param s string to be modified
     * @return string with escape characters, changed to html entities
     */
    public static String escapeText(String s) {
        if (s == null) {
            // shit in, shit out
            return null;
        }
        StringBuffer sb = new StringBuffer();
        int n = s.length();
        char c;
        String entity;
        for (int i = 0; i < n; i++) {
            c = s.charAt(i);
            entity = getEntityForChar(c);
            if (entity != null) {
                sb.append(entity);
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * change html entities to escape characters (from
     * http://www.rgagnon.com/howto.html)
     *
     * @param s string to unescape
     * @return new string with html entities changed to escape characters
     */
    public static String unescapeText(String s) {
        int i, j, k;
        int arraySize = HTML_ESCAPE_CHARS.length;
        if (s != null && (i = s.indexOf("&")) > -1) {
            j = s.indexOf(";", i);
            if (j > i) {
                String temp = s.substring(i, j + 1);
                // search in escape[][] if temp is there
                k = 0;
                while (k < arraySize) {
                    if (HTML_ESCAPE_CHARS[k][0].equals(temp)) {
                        break;
                    }
                    k++;
                }
                // now we found html escape character
                if (k < arraySize) {
                    // replace it to ASCII
                    s = new StringBuffer(s.substring(0, i))
                            .append(HTML_ESCAPE_CHARS[k][1])
                            .append(s.substring(j + 1)).toString();
                    return unescapeText(s); // recursive call
                } else if (k == arraySize) {
                    s = new StringBuffer(s.substring(0, i)).append("&")
                            .append(unescapeText(s.substring(i + 1)))
                            .toString();
                    return s;
                }
            }
        }
        return s;
    }

    public static String invertCase(String line) {
        char[] chars = line.toCharArray();
        char c;
        boolean changed = false;
        for (int i = 0; i < chars.length; i++) {
            c = chars[i];
            if (Character.isLowerCase(c)) {
                chars[i] = Character.toUpperCase(c);
                changed = true;
            } else if (Character.isUpperCase(c)) {
                chars[i] = Character.toLowerCase(c);
                changed = true;
            }
        }
        if (changed) {
            return String.valueOf(chars);
        }
        return line;
    }

    /**
     * 全角转半角 符号，数字，字母 高位为-1，低位全角比半角少32H。 将字母a-z,A-Z，0-9之外的符号转换成为半角。
     *
     * @param SBCString
     * @return 半角 String
     */
    public static String SBC2DBC(String SBCString) {
        if (SBCString == null) {
            return null;
        }
        StringBuffer DBCString = new StringBuffer("");
        SBCString = SBCString.replaceAll("　", " ");
        try {
            byte[] bytes = null;
            for (int i = 0; i < SBCString.length(); i++) {
                String temp = SBCString.substring(i, i + 1);
                boolean isContainLetters = Pattern.matches("[0-9a-zA-Z]", temp);
                if (!isContainLetters) {
                    bytes = temp.getBytes("unicode");
                    if (bytes[2] == -1) {
                        bytes[3] = (byte) (bytes[3] + 32);
                        bytes[2] = 0;
                    }
                    DBCString.append(new String(bytes, "unicode"));
                } else {
                    DBCString.append(temp);
                }
            }
        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage());
        }
        return DBCString.toString();
    }

    /**
     * 半角转全角 半角的 符号，数字，字母 高位为0，低位半角比全角多32H。 将字母a-z,A-Z，0-9之外的符号转换成 为全角，数据库存贮。
     *
     * @param DBCString
     * @return 全角 String
     */
    public static String DBC2SBC(String DBCString) {
        if (DBCString == null) {
            return null;
        }
        StringBuffer SBCString = new StringBuffer("");
        DBCString = DBCString.replaceAll(" ", "　");
        try {
            byte[] bytes = null;
            for (int i = 0; i < DBCString.length(); i++) {
                String temp = DBCString.substring(i, i + 1);
                boolean isContainLetters = Pattern.matches("[0-9a-zA-Z]", temp);
                if (!isContainLetters) {
                    bytes = temp.getBytes("unicode");
                    if (bytes[2] == 0) {
                        bytes[3] = (byte) (bytes[3] - 32);
                        bytes[2] = -1;
                    }
                    SBCString.append(new String(bytes, "unicode"));
                } else {
                    SBCString.append(temp);
                }
            }
        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage());
        }
        return SBCString.toString();
    }

    private static final String ENGLISH_STRING = "^[a-zA-Z_]*";

    public static boolean isEnglishString(String string) {
        return StringUtils.isNotBlank(string) && string.matches(ENGLISH_STRING);
    }

    public static String replaceBlank(String str) {
        String dest = "";
        if (str != null) {
            Pattern p = Pattern.compile("\\s*|\t|\r|\n");
            Matcher m = p.matcher(str);
            dest = m.replaceAll("");
        }
        return dest;
    }

    private static Pattern humpPattern = Pattern.compile("[A-Z]");

    /**
     * 驼峰转下划线
     */
    public static String camel2Underline(String str) {
        Matcher matcher = humpPattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    public static String nderline2Camel(String source) {
        boolean upper = false;
        StringBuilder sb = new StringBuilder();
        for (char c : source.toCharArray()) {
            if ('_' == c) {
                upper = true;
                continue;
            }
            sb.append(upper ? Character.toUpperCase(c) : Character.toLowerCase(c));
            upper = false;
        }
        return sb.toString();
    }

    private static final String HEX_CHAR = "0123456789ABCDEF";

    public static String toHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        if (bytes == null || bytes.length <= 0) {
            return null;
        }
        for (int i = 0; i < bytes.length; i++) {
            int h = (bytes[i] >> 4) & 0xF;
            int l = (bytes[i]) & 0xF;
            sb.append(HEX_CHAR.charAt(h));
            sb.append(HEX_CHAR.charAt(l));
        }
        return sb.toString();
    }

    public static String ignore(String value, int prefixCount, int suffixCount) {
        if (isBlank(value) || value.length() <= (prefixCount + suffixCount)) {
            return "*";
        }

        int size = value.length();
        String str = "***";

        return value.substring(0, prefixCount) + str
                + value.substring(size - suffixCount, size);
    }


    public static <T> List<String> buildModel(Collection<T> collection, Function<T, String> function) {
        Set<String> hashSet = new HashSet<>();
        List<String> list = new ArrayList<>();
        for (T model : collection) {
            String val = function.apply(model);
            if (!hashSet.contains(val) && StringUtils.isNotEmpty(val)) {
//                buffer.append(",").append("'").append(val).append("'");
                hashSet.add(val);
                list.add(val);
            }
        }
        return list;
    }


    public static <T> String buildModel(Collection<T> collection) {
        StringBuilder stringBuilder = new StringBuilder();
        List<String> list = new ArrayList<>();
        for (T model : collection) {
            stringBuilder.append(",").append("'").append(model).append("'");
        }
        return stringBuilder.toString();
    }

    /***
     * 生成规则
     * @param
     * @return
     */
    public static String createUniqueNo() {
        StringBuffer buffer = new StringBuffer();
        long millis = System.currentTimeMillis();
        final AtomicInteger incUnique = new AtomicInteger();
        int inc = incUnique.getAndIncrement() & ~((~0) << 5);
        return buffer.append(millis).append(inc).toString();
    }


    /**
     * 时间转换
     *
     * @param dateCahr
     * @return
     */
    public static LocalDateTime buildDate(String dateCahr) {
        Date date = DateUtils.toDate(dateCahr, DateUtils.FORMAT_DATE_TIME_DEFAULT);
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
        return localDateTime;
    }

    public static LocalDateTime buildTime(String dateCahr) {
        Date date = DateUtils.toDate(dateCahr, DateUtils.FORMAT_DATE_DEFAULT);
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
        return localDateTime;
    }

    /**
     * 将一个list均分成n个list,主要通过偏移量来实现的
     *
     * @param source
     * @return
     */
    public static <T> List<List<T>> averageAssign(List<T> source, int n) {
        List<List<T>> result = new ArrayList<List<T>>();
        int remaider = source.size() % n;  //(先计算出余数)
        int number = source.size() / n;  //然后是商
        int offset = 0;//偏移量
        for (int i = 0; i < n; i++) {
            List<T> value = null;
            if (remaider > 0) {
                value = source.subList(i * number + offset, (i + 1) * number + offset + 1);
                remaider--;
                offset++;
            } else {
                value = source.subList(i * number + offset, (i + 1) * number + offset);
            }
            result.add(value);
        }
        return result;
    }


    @SuppressWarnings({"unchecked", "rawtypes"})
    public static <T> List<List<T>> groupList(List<T> list, int toIndex) {
        int listSize = list.size();
        ArrayList<List<T>> arrayList = new ArrayList<>();//用map存起来新的分组后数据
        int keyToken = 0;
        for (int i = 0; i < list.size(); i += toIndex) {
            if (i + toIndex > listSize) {        //作用为toIndex最后没有100条数据则剩余几条newList中就装几条
                toIndex = listSize - i;
            }
            arrayList.add(list.subList(i, i + toIndex));

            keyToken++;
        }
        return arrayList;
    }


    public static boolean judge(Object object) {
        if (null != object) {
            return true;
        }
        return false;
    }


//    public void test(){
//        String dateTime = new SimpleDateFormat(DateUtil.yyyyMMdd).format(new Date());
//        String dictionaryCode = dateTime + "001";
//        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
//        PageRequest pageRequest = PageRequest.of(0, 1, sort);
//        Page<VisitMo> visitMoDaoAll = visitMoDao.findAll(pageRequest);
//        List<VisitMo> content = visitMoDaoAll.getContent();
//        if (CollectionUtils.isNotEmpty(content)) {
//            String serviceCode = content.get(0).getVisitMoId().substring(2, content.get(0).getVisitMoId().length());
//            if (Objects.nonNull(serviceCode)) {
//                String number = serviceCode.substring(0, 8);
//                if (dateTime.equals(number)) {
//                    String code = serviceCode.substring(8);
//                    dictionaryCode = dateTime + String.format("%03d", Integer.parseInt(code) + 1);
//                }
//            }
//        }
//        StringBuffer buffer = new StringBuffer();
//        buffer.append("MO").append(dictionaryCode);
//        return buffer.toString();
//    }


    /**
     * 生成的随机编码
     *
     * @param rule
     * @return
     */
    public static String randomGenerate(String rule) {
        StringBuilder sb = new StringBuilder();
        sb.append(rule);
        SecureRandom rand = new SecureRandom();
        int data = 0;
        for (int i = 0; i < 7; i++) {
            int index = rand.nextInt(3);
            //目的是随机选择生成数字，大小写字母
            switch (index) {
                case 0:
                    data = rand.nextInt(10);//仅仅会生成0~9
                    sb.append(data);
                    break;
                case 1:
                    data = rand.nextInt(26) + 65;//保证只会产生65~90之间的整数
                    sb.append((char) data);
                    break;
                case 2:
                    data = rand.nextInt(26) + 97;//保证只会产生97~122之间的整数
                    sb.append((char) data);
                    break;
            }
        }
        String result = sb.toString();
        logger.info("生成的随机编码为{}", result);
        return result;
    }


    /**
     * 对象首字母转大写
     *
     * @param
     * @return
     */
    public static <T> String InitialCaseConversion(T t) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            mapper.configure(MapperFeature.USE_STD_BEAN_NAMING, true);
            String json = mapper.writeValueAsString(t);
            return json;
        } catch (JsonProcessingException e) {
            logger.error(String.format("对象首字母转大写异常：&s", e));
        }
        return null;
    }

    /**
     * 名称脱敏
     *
     * @param name
     * @return
     */
    public static String maskName(String name) {
        if (name == null || name.isEmpty()) {
            return name;
        }
        int length = name.length();
        StringBuilder sb = new StringBuilder();
        sb.append(name.charAt(0));
        sb.append("*");
        if (length > 2) {
            sb.append(name.charAt(length - 1));
        }
        return sb.toString();
    }


    /**
     * 手机号脱敏
     *
     * @author tw
     * @date 2023/7/27
     */
    public static String maskMobileNumber(String mobileNumber) {
        if (mobileNumber == null || mobileNumber.length() < 11) {
            return mobileNumber;
        }
        String prefix = mobileNumber.substring(0, 3);
        String suffix = mobileNumber.substring(6);
        StringBuffer mask = new StringBuffer();
        for (int i = 0; i < mobileNumber.length() - 8; i++) {
            mask.append("*");
        }
        return prefix + mask + suffix;
    }


    /**
     * 邮箱脱敏
     *
     * @author tw
     * @date 2023/7/27
     */
    public static String maskEmail(String email) {
        if (email == null || email.isEmpty()) {
            return email;
        }
        // 使用 split 方法获取邮箱地址的用户名和域名部分
        String[] parts = email.split("@");
        if (parts.length != 2) {
            // 邮箱地址格式不正确，直接返回原始字符串
            return email;
        }
        String username = parts[0];
        String domain = parts[1];
        // 使用 substring 方法获取用户名的前三位和后两位
        String usernamePrefix = username.substring(0, username.length() - 1);
        String usernameSuffix = username.substring(username.length() - 1, username.length() - 2);
        StringBuffer mask = new StringBuffer();
        for (int i = 0; i < usernameSuffix.length(); i++) {
            mask.append("*");
        }
        // 拼接用户名的前缀、星号和后缀，得到脱敏后的邮箱地址
        String maskedEmail = usernamePrefix + mask + usernameSuffix + "@" + domain;
        return maskedEmail;
    }


    /**
     * 证件号脱敏
     *
     * @author tw
     * @date 2023/7/27
     */
    public static String maskIDCard(String idCard) {
        if (idCard == null || idCard.length() < 3) {
            return idCard;
        } else if (idCard.length() >= 18) {
            // 使用 substring 方法获取身份证号的前六位和后四位
            String prefix = idCard.substring(0, 4);
            String suffix = idCard.substring(idCard.length() - 4);
            StringBuffer mask = new StringBuffer();
            for (int i = 0; i < idCard.length() - 8; i++) {
                mask.append("*");
            }
            // 拼接前缀、星号和后缀，得到脱敏后的身份证号
            return prefix + mask + suffix;
        } else {
            // 使用 substring 方法获取护照号的前两位和后一位
            String prefix = idCard.substring(0, 2);
            String suffix = idCard.substring(idCard.length() - 4);
            StringBuffer mask = new StringBuffer();
            for (int i = 0; i < idCard.length() - 6; i++) {
                mask.append("*");
            }
            // 拼接前缀、星号和后缀，得到脱敏后的护照号
            return prefix + mask + suffix;
        }

    }

    /**
     * 地址脱敏
     *
     * @param address
     * @return
     */
    public static String maskAddress(String address) {
        if (address == null || address.isEmpty()) {
            return address;
        }
        StringBuilder sb = new StringBuilder();
        String[] split = address.split("");
        int j = 0;
        for (int i = 0; i < split.length; i++) {
            if (i < 3) {
                sb.append(split[i]);
            } else if (i > 3 && i < split.length - 1) {
                if (j < 3) {
                    sb.append("*");
                    j++;
                }
            } else if (i == split.length - 1) {
                sb.append(split[i]);
            }
        }
        return sb.toString();
    }


    /**
     * 邮箱脱敏
     *
     * @author tw
     * @date 2023/8/14
     */
    public static String desensitizeEmail(String email) {
        if (email == null || email.isEmpty()) {
            return email;
        }
        int atIndex = email.indexOf('@');
        if (atIndex > 0) {
            String username = email.substring(0, atIndex);
            String domain = email.substring(atIndex);
            if (username.length() > 3) {
                String maskedUsername = maskString(username, '*', 3);
                return maskedUsername + domain;
            } else if (username.length() > 1) {
                String maskedUsername = maskString(username, '*', 1);
                return maskedUsername + domain;
            } else {
                String maskedUsername = maskString(username, '*', 0);
                return maskedUsername + domain;
            }
        }
        return email;
    }

    private static String maskString(String str, char maskChar, int visibleChars) {
        int maskLength = Math.max(0, str.length() - visibleChars);
        String mask = new String(new char[maskLength]).replace('\0', maskChar);
        return mask + str.substring(maskLength);
    }

    public static int countSubstringOccurrences(String mainString, String substring) {
        int count = 0;
        int lastIndex = 0;
        while (lastIndex != -1) {
            lastIndex = mainString.indexOf(substring, lastIndex);

            if (lastIndex != -1) {
                count++;
                lastIndex += substring.length();
            }
        }
        return count;
    }


    public static String checkGender(String idCardNumber) {
        if (idCardNumber.length() == 18) {
            int genderDigit = Integer.parseInt(idCardNumber.substring(16, 17));
            return (genderDigit % 2 == 0) ? "F" : "M";
        }
        return "";
    }


    /**
     * 提前身份证生日
     *
     * @author tw
     * @date 2024/1/31
     */
    public static Date checkBirthday(String idCardNumber) {
        if (idCardNumber.length() == 18) {
            // 解析生日
            String year = idCardNumber.substring(6, 10);
            String month = idCardNumber.substring(10, 12);
            String day = idCardNumber.substring(12, 14);
            String date = year + "-" + month + "-" + day;
            return DateUtils.toDate(date);
        }
        return null;
    }


    /**
     * 手机号脱敏
     *
     * @author tw
     * @date 2023/7/27
     */
    public static String honeDesensitize(String mobileNumber) {
        if (mobileNumber == null || mobileNumber.length() < 11) {
            return mobileNumber;
        }
        String prefix = mobileNumber.substring(0, 3);
        String suffix = mobileNumber.substring(7);
        StringBuffer mask = new StringBuffer();
        for (int i = 0; i < mobileNumber.length() - 7; i++) {
            mask.append("*");
        }
        return prefix + mask + suffix;
    }


    /**
     * 校验手机格式
     *
     * @author tw
     * @date 2024/1/31
     */
    public static boolean checkMobile(String mobile) {
        String mobileFormat = "^1[0-9]{10}$";
        boolean isValid = Pattern.matches(mobileFormat, mobile);
        return isValid;
    }


    /**
     * 校验邮箱格式
     *
     * @author tw
     * @date 2024/1/31
     */
    public static boolean checkEmail(String email) {
        final String emailFormat = "^([0-9a-zA-Z]+[-._+&])*[0-9a-zA-Z]+@([-0-9a-zA-Z]+[.])+[a-zA-Z]{2,6}$";
        boolean isValid = Pattern.matches(emailFormat, email);
        return isValid;
    }

    public static void main(String[] args) {
        System.out.println(checkChEn("A/BC"));
    }

    public static boolean checkChEn(String name) {
        String[] split = name.split("/");
        if (split.length == 1) {
            String regex = "[\\u4e00-\\u9fa5]+";  // 中文字符的正则表达式
            boolean isValid = Pattern.matches(regex, name);
            return isValid;
        } else {
            String regexEn = "^[a-zA-Z]+$";  // 英文字符的正则表达式
            boolean formerName = Pattern.matches(regexEn, split[0]);
            boolean lastName = Pattern.matches(regexEn, split[1]);
            if (formerName && lastName) {
                return true;
            }
            return false;
        }
    }



    public static List<String> nameDismantling(String name) {
        List<String> nameList = new ArrayList<>();
        String[] split = name.split("/");
        if (split.length > 1) {
            nameList.add(split[0]);
            nameList.add(split[1]);
        } else {
            int length = name.length();
            String fristName = name.substring(0, 1);
            String lastName = name.substring(1, length);
            nameList.add(fristName);
            nameList.add(lastName);
        }
        return nameList;
    }


}
